home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 August: Tool Chest / Dev.CD Aug 00 TC Disk 2.toast / pc / sample code / quicktime / codecs / examplecodec / examplecodec.c next >
Encoding:
C/C++ Source or Header  |  2000-06-23  |  38.5 KB  |  1,355 lines

  1. /*
  2.     File:        examplecodec.c
  3.  
  4.     Contains:    This is an example of am image compression codec that handles both
  5.                 compression and decompression of images as passed to it by the 
  6.                 Image Compression manager. It is built as a Component Manager Component.
  7.  
  8.  
  9.                 The compression scheme here is 411 YUV. The image is stored as separate 
  10.                 luminance and chrominance channels. For each 2x2 block of pixels in the
  11.                 source image we store 4 luminance (Y) components, 1 Y-Red component (U) and
  12.                 1 Y-Blue (V) component. Each Y-component is stored as 6-bits,  resulting in a 
  13.                 savings of 2.4:1 over a 24-bit/pixel image (6*4 + 2*8)/4 = 10 bits/pixel.
  14.     
  15.     Written by:     
  16.  
  17.     Copyright:    Copyright © 1999 by Apple Computer, Inc., All Rights Reserved.
  18.  
  19.                 You may incorporate this Apple sample source code into your program(s) without
  20.                 restriction. This Apple sample source code has been provided "AS IS" and the
  21.                 responsibility for its operation is yours. You are not permitted to redistribute
  22.                 this Apple sample source code as "Apple sample source code" after having made
  23.                 changes. If you're going to re-distribute the source, we require that you make
  24.                 it clear in the source that the code was descended from Apple sample source
  25.                 code, but that you've made changes.
  26.  
  27.     Change History (most recent first):
  28.                 7/29/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
  29.                 
  30.  
  31. */
  32.  
  33.  
  34. #include <Memory.h>
  35. #include <Resources.h>
  36. #include <QuickDraw.h>    
  37. #include <QDOffscreen.h>
  38. #include <OSUtils.h>
  39. #include <Errors.h>
  40. #include <FixMath.h>
  41.  
  42. #include "ImageCodec.h"
  43.  
  44.  
  45.  
  46. /* Version information */
  47.  
  48. #define    EXAMPLE_CODEC_REV            1
  49. #define    codecInterfaceVersion        1                /* high word returned in component GetVersion */
  50.  
  51.  
  52.  
  53. /* Some useful macros and constants */
  54.  
  55.  
  56. #define    R_W    0x4ccd
  57. #define    G_W    0x970a
  58. #define    B_W    0x1c29
  59. #define    PIN(_n)        ((_n) < 0 ? 0 : (_n) > 255 ? 255 : (_n))
  60.  
  61.  
  62. /*
  63.     Our data structure declarations
  64. */
  65.  
  66.  
  67.  
  68. /* This is the structure we use to hold data used by all instances of
  69.    this compressor and decompressor */
  70.  
  71. typedef struct    {                    
  72.     Handle    rgbwTable;                    /* optional encode/decode table */
  73.     Handle    giwTable;                    /* another optional encode/decode table */
  74.     CodecInfo    **info;                    /* our cached codec info structure */
  75. } SharedGlobals;
  76.  
  77.  
  78. /* This is the structure we use to store our global data for each instance */
  79.  
  80. typedef struct    {                        
  81.     SharedGlobals    *sharedGlob;        /* pointer to instance-shared globals */
  82. } Globals;
  83.  
  84.  
  85. /* Function prototypes to keep the compiler smiling. */
  86. ComponentResult
  87. InitSharedTables(Globals **glob,ComponentInstance self);
  88.  
  89. pascal ComponentResult
  90. EXAMPLECODEC(ComponentParameters *params,char **storage);
  91.  
  92. pascal ComponentResult
  93. OpenCodec(ComponentInstance self);
  94.  
  95. pascal ComponentResult
  96. CloseCodec(Handle storage,ComponentInstance self);
  97.  
  98. pascal ComponentResult
  99. CanDoSelector(short selector);
  100.  
  101. pascal ComponentResult 
  102. GetVersion();
  103.  
  104. pascal void
  105. CompressStrip(char *data,char *baseAddr,short rowBytes,short w,SharedGlobals *sg);
  106.  
  107. pascal void
  108. DecompressStrip(char *data,char *baseAddr,short rowBytes,short w,SharedGlobals *sg);
  109.  
  110.  
  111. pascal long
  112. CDPreCompress(Handle storage,register CodecCompressParams *p);
  113. pascal long
  114. CDBandCompress(Handle storage,register CodecCompressParams *p);
  115. pascal long
  116. CDPreDecompress(Handle storage,register CodecDecompressParams *p);
  117. pascal long
  118. CDBandDecompress(Handle storage,register CodecDecompressParams *p);
  119. pascal ComponentResult
  120. CDGetCodecInfo(Handle storage,CodecInfo *info);
  121. pascal ComponentResult
  122. CDGetSimilarity(Handle storage,PixMapHandle src,const Rect *srcRect,ImageDescriptionHandle desc,
  123.                 Ptr data,Fixed *similarity);
  124. pascal ComponentResult
  125. CDGetCompressedImageSize(Handle storage,ImageDescriptionHandle desc,Ptr data,long dataSize,
  126.     ICMDataProcRecordPtr dataProc,long *size);
  127. pascal ComponentResult
  128. CDGetMaxCompressionSize(Handle storage,PixMapHandle src,const Rect *srcRect,short depth,
  129.     CodecQ quality,long *size);
  130.     pascal ComponentResult
  131. CDGetCompressionTime(Handle storage,PixMapHandle src,const Rect *srcRect,short depth,
  132.         CodecQ *spatialQuality,CodecQ *temporalQuality,unsigned long *time);
  133.         pascal ComponentResult
  134. CDTrimImage(Handle storage,ImageDescriptionHandle desc,Ptr inData,long inDataSize,
  135.         ICMDataProcRecordPtr dataProc,Ptr outData,long outDataSize,ICMFlushProcRecordPtr flushProc,
  136.         Rect *trimRect,ICMProgressProcRecordPtr progressProc);
  137. pascal void
  138. CompressStrip(char *data,char *baseAddr,short rowBytes,short len,SharedGlobals *sg);
  139.  
  140. /************************************************************************************ 
  141.  *    This is the main dispatcher for our codec. All calls from the codec manager
  142.  *    will come through here, with a unique selector and corresponding parameter block.
  143.  *
  144.  *    This routine must be first in the code segment of the codec thing.
  145.  */
  146.  
  147. pascal ComponentResult
  148. EXAMPLECODEC(ComponentParameters *params,char **storage)
  149. {
  150.     /*    If the selector is less than zero, it's a Component manager selector.    */
  151.     
  152.     if ( params->what < 0  ) { 
  153.         switch ( params->what ) {
  154.         case kComponentOpenSelect:
  155.             return CallComponentFunction(params, (ComponentFunctionUPP) OpenCodec );
  156.  
  157.         case    kComponentCloseSelect:
  158.             return CallComponentFunctionWithStorage(storage,params,(ComponentFunctionUPP) CloseCodec );
  159.             
  160.         case    kComponentCanDoSelect:
  161.             return CallComponentFunction(params, (ComponentFunctionUPP) CanDoSelector);
  162.  
  163.         case kComponentVersionSelect : 
  164.             return CallComponentFunction(params, (ComponentFunctionUPP) GetVersion);
  165.  
  166.         default :
  167.             return (paramErr);
  168.         }
  169.     }
  170.     
  171.     /*
  172.      *    Here we dispatch the rest of our calls. We use the magic thing manager routine which
  173.      *    calls our subroutines with the proper parameters. The prototypes are in Image Codec.h.
  174.      */
  175.     
  176.     switch ( params->what ) {
  177.     case kImageCodecPreCompressSelect:    
  178.         return CallComponentFunctionWithStorage(storage,params,(ComponentFunctionUPP)CDPreCompress);
  179.         
  180.     case kImageCodecBandCompressSelect:
  181.         return CallComponentFunctionWithStorage(storage,params,(ComponentFunctionUPP)CDBandCompress);
  182.         
  183.     case kImageCodecPreDecompressSelect:
  184.         return CallComponentFunctionWithStorage(storage,params,(ComponentFunctionUPP)CDPreDecompress);
  185.  
  186.     case kImageCodecBandDecompressSelect:
  187.         return CallComponentFunctionWithStorage(storage,params,(ComponentFunctionUPP)CDBandDecompress);
  188.  
  189.     case kImageCodecBusySelect:
  190.         return 0;                    /* our codec is never asynchronously busy */
  191.  
  192.     case kImageCodecGetCodecInfoSelect:
  193.         return CallComponentFunctionWithStorage(storage,params,(ComponentFunctionUPP)CDGetCodecInfo);
  194.         
  195.     case kImageCodecGetCompressedImageSizeSelect:
  196.         return CallComponentFunctionWithStorage(storage,params,(ComponentFunctionUPP)CDGetCompressedImageSize);
  197.  
  198.     case kImageCodecGetMaxCompressionSizeSelect:
  199.         return CallComponentFunctionWithStorage(storage,params,(ComponentFunctionUPP)CDGetMaxCompressionSize);
  200.  
  201.     case kImageCodecGetCompressionTimeSelect:
  202.         return CallComponentFunctionWithStorage(storage,params,(ComponentFunctionUPP)CDGetCompressionTime);
  203.  
  204.     case kImageCodecGetSimilaritySelect:
  205.         return CallComponentFunctionWithStorage(storage,params,(ComponentFunctionUPP)CDGetSimilarity);
  206.  
  207.     case kImageCodecTrimImageSelect:
  208.         return CallComponentFunctionWithStorage(storage,params,(ComponentFunctionUPP)CDTrimImage);
  209.     
  210.     default:
  211.         return(paramErr);
  212.     }    
  213. }
  214.  
  215. /************************************************************************************ 
  216.  *    This gets called when the thing instance is opened. We allocate our storage at this
  217.  *    point. If we have shared globals, we check if they exist, and put a pointer to them 
  218.  *    in our instance globals so that other calls can get to them.
  219.  */
  220.  
  221. pascal ComponentResult
  222. OpenCodec(ComponentInstance self)
  223. {
  224.     ComponentResult result;
  225.     Globals             **glob;
  226.     
  227.     /* 
  228.         First we allocate shared storage. This should be a handle to any
  229.         kind of data used by the thing instance. They should be allocated
  230.         in the current heap.
  231.     
  232.     */     
  233.          
  234.     if ( (glob = (Globals **)NewHandleClear(sizeof(Globals))) == nil )  {
  235.         return(MemError());
  236.     }
  237.     SetComponentInstanceStorage(self,(Handle)glob);
  238.     
  239.     /*     Check and initialize our shared globals */
  240.     
  241.     result = InitSharedTables(glob,self);
  242.     
  243.     return result;
  244. }
  245.  
  246. /************************************************************************************ 
  247.  *    This gets called when the thing instance is opened. We allocate our shared storage at this
  248.  *    point. 
  249.  
  250.  *    If we have shared globals, we check if they exist, otherwise we allocate
  251.  *  them and set the ComponentRefCon so that other instances can use them.
  252.  *
  253.  *    The shared globals hold our CodecInfo struct, which we read from our resource file,
  254.  *  and some tables that we use for speed. If we cant get the tables we can work without
  255.  *  them. All items in the shared globals are made purgeable when the last of our 
  256.  *    instances is closed. If our component was loaded in the application heap ( because
  257.  *    there was no room in the system heap) then we keep our shared storage in the app heap.
  258.  *
  259.  *  We keep a pointer to the shared globals in our instance globals so that other calls can get to them.
  260.  */
  261.  
  262.  
  263. ComponentResult
  264. InitSharedTables(Globals **glob,ComponentInstance self)
  265. {
  266.     SharedGlobals    *sGlob;
  267.     long            i,j,*lp;
  268.     char            *cp;
  269.     short            resFile;
  270.     THz                saveZone;
  271.     Boolean            inAppHeap;
  272.     OSErr            result = noErr;
  273.         
  274.      
  275.     saveZone = GetZone();
  276.     inAppHeap = ( GetComponentInstanceA5(self) != 0 );
  277.     if ( !inAppHeap )
  278.         SetZone(SystemZone());
  279.     if ( (sGlob=(SharedGlobals*)GetComponentRefcon((Component)self)) == nil  ) {
  280.         if ( (sGlob = (SharedGlobals*)NewPtrClear(sizeof(SharedGlobals))) == nil ) { 
  281.             result = MemError();
  282.             goto obail;
  283.         } 
  284.         SetComponentRefcon((Component)self,(long)sGlob);
  285.     }
  286.  
  287.     (*glob)->sharedGlob = sGlob;    // keep this around where it's easy to get at
  288.     
  289.  
  290.     if ( sGlob->info == nil || *(Handle)sGlob->info == nil  )  {
  291.  
  292.         if ( sGlob->info ) 
  293.             DisposeHandle((Handle)sGlob->info);
  294.  
  295.         /* Get the CodecInfo struct which we keep in our resource fork */
  296.         
  297.         resFile = OpenComponentResFile((Component)self);
  298.         if (resFile == -1) {
  299.             result = memFullErr;
  300.             goto obail;
  301.         }
  302.         sGlob->info = (CodecInfo **) Get1Resource(codecInfoResourceType,128);
  303.         if ( sGlob->info == nil ) {
  304.             CloseComponentResFile(resFile);
  305.             result = ResError();
  306.             goto obail;
  307.         }
  308.         LoadResource((Handle)sGlob->info);
  309.         if ( ResError() ) {
  310.             CloseComponentResFile(resFile);
  311.             result = ResError();
  312.             goto obail;
  313.         }
  314.         DetachResource((Handle)sGlob->info);
  315.         CloseComponentResFile(resFile);
  316.     }
  317.     HNoPurge((Handle)sGlob->info);
  318.     
  319.     if ( sGlob->rgbwTable == nil || *sGlob->rgbwTable == nil )  {
  320.         if ( sGlob->rgbwTable )
  321.             ReallocateHandle(sGlob->rgbwTable,3*256*sizeof(long));
  322.         else 
  323.             sGlob->rgbwTable = NewHandleSys(3*256*sizeof(long));
  324.             
  325.         /* we can actual still work without these tables, so we dont bail
  326.            if we cant get the memory for them */
  327.            
  328.         if ( sGlob->rgbwTable  && *sGlob->rgbwTable ) {
  329.             lp = (long *)*sGlob->rgbwTable;
  330.             for ( i=0, j = 0; i < 256; i++, j += R_W )
  331.                 *lp++ = j;
  332.             for ( i=0, j = 0; i < 256; i++, j += G_W )
  333.                 *lp++ = j;
  334.             for ( i=0, j = 0; i < 256; i++, j += B_W )
  335.                 *lp++ = j;
  336.         }
  337.     }
  338.     if ( sGlob->rgbwTable ) 
  339.         HNoPurge(sGlob->rgbwTable);            /* make sure it wont get purged while we are open */
  340.     
  341.     /* green inverse table */
  342.  
  343.     if ( sGlob->giwTable == nil || *sGlob->giwTable == nil  )  {
  344.         if ( sGlob->giwTable ) 
  345.             ReallocateHandle(sGlob->giwTable,256);
  346.         else 
  347.             sGlob->giwTable = NewHandleSys(256);
  348.  
  349.         /* we can actual still work without these tables, so we dont bail
  350.            if we cant get hte memory for them */
  351.  
  352.         if ( sGlob->giwTable && *sGlob->giwTable  ) {
  353.             for ( i=0, cp = *sGlob->giwTable ; i < 256; i++ )
  354.                 *cp++ = PIN( (i<<16) / G_W);
  355.         }
  356.     }
  357.     if ( sGlob->giwTable ) 
  358.         HNoPurge(sGlob->giwTable);            /* make sure it wont get purged while we are open */
  359.  
  360.  
  361. obail:
  362.  
  363.     SetZone(saveZone);
  364.     if ( result != noErr && sGlob != nil ) {
  365.         if ( sGlob->rgbwTable )
  366.             DisposeHandle(sGlob->rgbwTable);
  367.         if ( sGlob->info )
  368.             DisposeHandle((Handle)sGlob->info);
  369.         DisposePtr((Ptr)sGlob);
  370.         SetComponentRefcon((Component)self,(long)nil);
  371.     }
  372.     return(result);
  373. }
  374.  
  375. /************************************************************************************ 
  376.  *    This gets called when the thing instance is closed. We need to get rid of any 
  377.  *    instance storage here. 
  378.  */
  379.  
  380. pascal ComponentResult
  381. CloseCodec(Handle storage,ComponentInstance self)
  382. {
  383.     SharedGlobals    *sGlob;
  384.     Globals            **glob = (Globals **)storage;
  385.         
  386.     /*    If we are closing our last instance 
  387.         then we make the shared global items purgeable to
  388.         speed things up next instance.
  389.      */
  390.     
  391.     if ( CountComponentInstances((Component)self) == 1) {
  392.         if ( (sGlob=(SharedGlobals*)(*glob)->sharedGlob) != nil  ) {
  393.             if ( sGlob->rgbwTable )
  394.                 HPurge(sGlob->rgbwTable);
  395.             if ( sGlob->giwTable )
  396.                 HPurge(sGlob->giwTable);
  397.             if ( sGlob->info )
  398.                 HPurge((Handle)sGlob->info);
  399.         }
  400.     }
  401.     if ( glob )    
  402.         DisposeHandle((Handle)glob);
  403.     return(noErr);
  404. }
  405.  
  406.  
  407.  
  408. /************************************************************************************ 
  409.  *     Return true if we can handle the selector, otherwise false.
  410.  */
  411.  
  412. pascal ComponentResult
  413. CanDoSelector(short selector)
  414. {    
  415.     switch(selector) {
  416.         case kComponentOpenSelect:
  417.         case kComponentCloseSelect:
  418.         case kComponentCanDoSelect:
  419.         case kComponentVersionSelect : 
  420.         case kImageCodecPreCompressSelect:
  421.         case kImageCodecBandCompressSelect:
  422.         case kImageCodecPreDecompressSelect:
  423.         case kImageCodecBandDecompressSelect:
  424.         case kImageCodecBusySelect:
  425.         case kImageCodecGetCodecInfoSelect:
  426.         case kImageCodecGetCompressedImageSizeSelect:
  427.         case kImageCodecGetMaxCompressionSizeSelect:
  428.         case kImageCodecGetCompressionTimeSelect:
  429.         case kImageCodecGetSimilaritySelect:
  430.         case kImageCodecTrimImageSelect:
  431.             return(true);
  432.         default:
  433.             return (false);
  434.     }
  435. }
  436.  
  437.  
  438. /************************************************************************************ 
  439.  *    Return the version of this component ( defines interface ) and revision level
  440.  *    of the code.
  441.  */
  442.  
  443. pascal ComponentResult 
  444. GetVersion()
  445. {
  446.     return ((codecInterfaceVersion<<16) | EXAMPLE_CODEC_REV);        /* interface version in hi word, code rev in lo word  */
  447. }
  448.  
  449.  
  450. /************************************************************************************ 
  451.  *    CDPreCompress gets called before an image is compressed, or whenever the source pixmap
  452.  *    pixel size changes when compressing a sequence. We return information about
  453.  *    how we can compress the image to the codec manager, so that it can fit the source data
  454.  *    to our requirements. The ImageDescriptor is already filled in, so we can use it for 
  455.  *    reference (or even add to it ). PixelSize is the pixel depth of the source pixmap, we
  456.  *    use this as a reference for deciding what we can do. The other parameters return information
  457.  *    to the CodecManager about what we can do. We can also do setup here if we want to.
  458.  */
  459.  
  460. pascal long
  461. CDPreCompress(Handle storage,register CodecCompressParams *p)
  462. {
  463.     #pragma unused(storage)
  464.     CodecCapabilities *capabilities = p->capabilities;
  465.  
  466.     /*
  467.      *    First we return which depth input pixels we can deal with - based on what the
  468.      *    app has available - we can only work with 32 bit input pixels.
  469.      */
  470.        
  471.     switch ( (*p->imageDescription)->depth )  {
  472.         case 16:
  473.             capabilities->wantedPixelSize = 32;
  474.             break;
  475.         default:
  476.             return(codecConditionErr);
  477.             break;
  478.     }
  479.  
  480.     /* if the buffer gets banded,  return the smallest one we can deal with */
  481.     
  482.     capabilities->bandMin = 2;
  483.  
  484.     /* if the buffer gets banded, return the increment it be should grown */
  485.  
  486.     capabilities->bandInc = 2;
  487.     
  488.     
  489.     /*
  490.      *    If a codec needs the dimensions of the source pixmap to be of certain multiples
  491.      *    it can ask for the image to be extended out (via pixel replication) vertically
  492.      *    and/or horizontally.
  493.      *
  494.      *    In our case, we're dealing with 2 by 2 blocks and therefore we want the image
  495.      *    height and width to both be multiples of 2.  If either dimension is odd, we
  496.      *    ask it have it extended by one pixel.
  497.      */
  498.  
  499.     capabilities->extendWidth = (*p->imageDescription)->width & 1;
  500.     capabilities->extendHeight = (*p->imageDescription)->height & 1;
  501.     
  502.     return(noErr);
  503. }
  504.  
  505.  
  506. /************************************************************************************ 
  507.  *    CDBandCompress gets called when the codec manager wants us to compress an image, or a horizontal 
  508.  *    band of an image. The pixel data at sBaseAddr is guaranteed to conform to the criteria we 
  509.  *    demanded in BeginCompress.
  510.  */
  511.  
  512. pascal long
  513. CDBandCompress(Handle storage,register CodecCompressParams *p)
  514. {
  515.     short                width,height;
  516.     Ptr                    cDataPtr,dataStart;
  517.     short                depth;
  518.     Rect                sRect;
  519.     long                offsetH,offsetV;
  520.     Globals                **glob  = (Globals **)storage;
  521.     register char         *baseAddr;
  522.     long                numLines,numStrips;
  523.     short                rowBytes;
  524.     long                stripBytes;
  525.     char                mmuMode = 1;
  526.     register short        y;
  527.     ImageDescription    **desc = p->imageDescription;
  528.     OSErr                result = noErr;
  529.     
  530.     /*    If there is a progress proc, give it an open call at the start of this band. */
  531.  
  532.     if (p->progressProcRecord.progressProc)
  533.         CallICMDataProc(p->progressProcRecord.progressProc,codecProgressOpen,0,
  534.             p->progressProcRecord.progressRefCon);
  535.  
  536.     width = (*desc)->width;
  537.     height = (*desc)->height;
  538.     depth = (*desc)->depth;
  539.     dataStart = cDataPtr = p->data;
  540.  
  541.     /* figure out offset to first pixel in baseAddr from the pixelsize and bounds */
  542.  
  543.     rowBytes = p->srcPixMap.rowBytes & 0x3fff;
  544.     sRect =  p->srcPixMap.bounds;
  545.     numLines = p->stopLine - p->startLine;        /* number of scanlines in this band */
  546.     numStrips = (numLines+1)>>1;                /* number of strips in this band */
  547.     stripBytes = ((width+1)>>1) * 5;
  548.     
  549.     /* adjust the source baseAddress to be at the beginning of the desired rect */
  550.  
  551.     switch ( p->srcPixMap.pixelSize ) {
  552.     case 32:
  553.         offsetH = sRect.left<<2;
  554.         break;
  555.     case 16:
  556.         offsetH = sRect.left<<1;
  557.         break;
  558.     case 8:
  559.         offsetH = sRect.left;
  560.         break;
  561.     default:
  562.         result = codecErr;
  563.         goto bail;
  564.     }
  565.     offsetV = sRect.top * rowBytes;
  566.     baseAddr = p->srcPixMap.baseAddr + offsetH + offsetV;
  567.  
  568.  
  569.     /* if there is not a flush proc, adjust the pointer to the next band */
  570.     
  571.     if (  p->flushProcRecord.flushProc == nil )
  572.         cDataPtr += (p->startLine>>1) * stripBytes;
  573.     else {
  574.         if ( p->bufferSize < stripBytes ) {
  575.             result = codecSpoolErr;
  576.             goto bail;
  577.         }
  578.     }
  579.  
  580.  
  581.     /* do the slower flush/progress case if we have too */
  582.     
  583.     if (  p->flushProcRecord.flushProc  || p->progressProcRecord.progressProc ) {
  584.         SharedGlobals *sg = (*glob)->sharedGlob;
  585.  
  586.  
  587.         for ( y=0; y < numStrips; y++) {
  588.             SwapMMUMode(&mmuMode);
  589.             CompressStrip(cDataPtr,baseAddr,rowBytes,width,sg);
  590.             SwapMMUMode(&mmuMode);
  591.             baseAddr += rowBytes<<1;
  592.             if ( p->flushProcRecord.flushProc ) { 
  593.                 if (( result=CallICMFlushProc(p->flushProcRecord.flushProc,cDataPtr,stripBytes,
  594.                         p->flushProcRecord.flushRefCon)) != noErr) {
  595.                     result = codecSpoolErr;
  596.                     goto bail;
  597.                 }
  598.             } else {
  599.                 cDataPtr += stripBytes;
  600.             }
  601.             if (p->progressProcRecord.progressProc) {
  602.                 if(( result=CallICMProgressProc(p->progressProcRecord.progressProc,codecProgressUpdatePercent,
  603.                     FixDiv(y,numStrips),p->progressProcRecord.progressRefCon)) != noErr ) {
  604.                         result = codecAbortErr;
  605.                         goto bail;
  606.                     }
  607.             }
  608.         }
  609.     } else {
  610.         SharedGlobals *sg = (*glob)->sharedGlob;
  611.         short    tRowBytes = rowBytes<<1;
  612.  
  613.         SwapMMUMode(&mmuMode);
  614.         for ( y=numStrips; y--; ) {
  615.             CompressStrip(cDataPtr,baseAddr,rowBytes,width,sg);
  616.             cDataPtr += stripBytes;
  617.             baseAddr += tRowBytes;
  618.         }
  619.         SwapMMUMode(&mmuMode);
  620.     }
  621.  
  622.     /*
  623.     
  624.         return size and similarity on the last band 
  625.         
  626.     */
  627.     
  628.     if ( p->conditionFlags & codecConditionLastBand ) {
  629.         (*p->imageDescription)->dataSize = stripBytes * ((height+1)>>1);    /* return the actual size of the compressed data */
  630.         p->similarity = 0;                            /* we don't do frame differencing */
  631.     }
  632.     
  633. bail:
  634.     /*    If there is a progress proc, give it a close call at the end of this band. */
  635.  
  636.     if (p->progressProcRecord.progressProc)
  637.         CallICMProgressProc(p->progressProcRecord.progressProc,codecProgressClose,0,
  638.             p->progressProcRecord.progressRefCon);
  639.         
  640.     return(result);
  641. }
  642.  
  643.  
  644.  
  645. /************************************************************************************ 
  646.  *    CDPreDecompress gets called before an image is decompressed. We return information about
  647.  *    how we can decompress the image to the codec manager, so that it can fit the destination data
  648.  *    to our requirements. 
  649.  */
  650.  
  651. pascal long
  652. CDPreDecompress(Handle storage,register CodecDecompressParams *p)
  653. {
  654.     #pragma unused(storage)
  655.     register CodecCapabilities    *capabilities = p->capabilities;
  656.     Rect    dRect = p->srcRect;
  657.     
  658.     /*    Check if the matrix is okay for us. We don't do anything fancy. */
  659.     
  660.     if ( !TransformRect(p->matrix,&dRect,nil) )
  661.         return(codecConditionErr);
  662.  
  663.  
  664.     /*    Decide which depth compressed data we can deal with. */
  665.     
  666.     switch ( (*p->imageDescription)->depth )  {
  667.         case 16:
  668.             break;
  669.         default:
  670.             return(codecConditionErr);
  671.             break;
  672.     }
  673.     
  674.     /*    We can deal only 32 bit pixels. */
  675.  
  676.     capabilities->wantedPixelSize = 32;    
  677.     
  678.     /*    The smallest possible band we can do is 2 scan lines. */
  679.     
  680.     capabilities->bandMin = 2;
  681.  
  682.     /*    We can deal with 2 scan line high bands. */
  683.  
  684.     capabilities->bandInc = 2;
  685.     
  686.     /*    If we needed our pixels to be aligned on some integer multiple we would set these to
  687.      *    the number of pixels we need the dest extended by. If we dont care, or we take care of
  688.      *  it ourselves we set them to zero.
  689.      */
  690.  
  691.     capabilities->extendWidth = p->srcRect.right & 1;
  692.     capabilities->extendHeight = p->srcRect.bottom & 1;
  693.     
  694.     return(noErr);
  695. }
  696.  
  697.  
  698. /************************************************************************************ 
  699.  *    CDBandDecompress gets called when the codec manager wants us to decompress an image or a horizontal 
  700.  *    band of an image. The pixel data at baseAddr is guaranteed to conform to the criteria we 
  701.  *    demanded in BeginDecompress. If maskIn is true, then the mask data at mBaseAddr is valid, and
  702.  *    we need to clear bits in it that correspond to any pixels in the destination we do not want to 
  703.  *    change. ( We always write all pixels, so we dont care. This mode is important only for those
  704.  *    codecs that have frame differencing and don't always write all the pixels. )
  705.  */
  706.  
  707. pascal long
  708. CDBandDecompress(Handle storage,register CodecDecompressParams *p)
  709. {
  710.     Rect                dRect;
  711.     long                offsetH,offsetV;
  712.     Globals                **glob  = (Globals **)storage;
  713.     long                numLines,numStrips;
  714.     short                rowBytes;
  715.     long                stripBytes;
  716.     short                width;
  717.     register short        y;
  718.     register char        *baseAddr;
  719.     char                *cDataPtr;
  720.     char                mmuMode = 1;
  721.     OSErr                result = noErr;
  722.     
  723.     /*    Calculate the real base address based on the bounds rect. If it's not 
  724.         a linear transformation, we dont do it. */
  725.  
  726.     dRect = p->srcRect;
  727.     if ( !TransformRect(p->matrix,&dRect,nil) )
  728.         return(paramErr);
  729.  
  730.     /*    If there is a progress proc, give it an open call at the start of this band. */
  731.  
  732.     if (p->progressProcRecord.progressProc)
  733.         CallICMProgressProc(p->progressProcRecord.progressProc,codecProgressOpen,0,
  734.             p->progressProcRecord.progressRefCon);
  735.     
  736.     
  737.     /* initialize some local variables */
  738.     
  739.     width = (*p->imageDescription)->width;
  740.     rowBytes = p->dstPixMap.rowBytes;                    
  741.     numLines = p->stopLine - p->startLine;            /* number of scanlines in this band */
  742.     numStrips = (numLines+1)>>1;                    /* number of strips in this band */
  743.     stripBytes = ((width+1)>>1) * 5;                /* number of bytes in one strip of blocks */
  744.     cDataPtr = p->data;
  745.     
  746.     /* adjust the destination baseaddress to be at the beginning of the desired rect */
  747.     
  748.     offsetH = (dRect.left - p->dstPixMap.bounds.left);
  749.     switch (  p->dstPixMap.pixelSize ) {
  750.     case 32:
  751.         offsetH <<=2;                    /* 1 pixel = 4 bytes */
  752.         break;
  753.     case 16:
  754.         offsetH <<=1;                    /* 1 pixel = 2 bytes */
  755.         break;
  756.     case 8:                                
  757.         break;                            /* 1 pixel = 1 byte */
  758.     default:
  759.         result = codecErr;                /* we dont handle these cases, thow we could */
  760.         goto bail;
  761.     }
  762.     offsetV = (dRect.top - p->dstPixMap.bounds.top) * rowBytes;
  763.     baseAddr = p->dstPixMap.baseAddr + offsetH + offsetV;
  764.  
  765.  
  766.     /* 
  767.      *    If we are skipping some data, we just skip it here. We can tell because
  768.      *    firstBandInFrame says this is the first band for a new frame, and
  769.      *    if startLine is not zero, then that many lines were clipped out.
  770.      */
  771.  
  772.     if ( (p->conditionFlags & codecConditionFirstBand) && p->startLine != 0 ) {
  773.         if ( p->dataProcRecord.dataProc ) {
  774.             for ( y=0; y  < p->startLine>>1; y++ )  {
  775.                 if ( (result=CallICMDataProc(p->dataProcRecord.dataProc,&cDataPtr,stripBytes,
  776.                         p->dataProcRecord.dataRefCon)) != noErr ) {
  777.                     result = codecSpoolErr;
  778.                     goto bail;
  779.                 }
  780.                 cDataPtr += stripBytes;
  781.             }
  782.         } else
  783.             cDataPtr += (p->startLine>>1) * stripBytes;
  784.     }
  785.     
  786.     /*
  787.      *    If theres a dataproc spooling the data to us, then we have to do the data
  788.      *    in whatever size chunks they want to give us, or if there is a progressProc
  789.      *  make sure to call it as we go along.
  790.      */
  791.     
  792.     if ( p->dataProcRecord.dataProc || p->progressProcRecord.progressProc ) {
  793.         SharedGlobals *sg = (*glob)->sharedGlob;
  794.     
  795.         for (y=0; y < numStrips; y++) {
  796.             if (p->dataProcRecord.dataProc) {
  797.                 if ( (result=CallICMDataProc(p->dataProcRecord.dataProc,&cDataPtr,stripBytes,
  798.                         p->dataProcRecord.dataRefCon)) != noErr ) {
  799.                     result = codecSpoolErr;
  800.                     goto bail;
  801.                 }
  802.             }
  803.             SwapMMUMode(&mmuMode);
  804.             DecompressStrip(cDataPtr,baseAddr,rowBytes,width,sg);
  805.             SwapMMUMode(&mmuMode);
  806.             baseAddr += rowBytes<<1;
  807.             cDataPtr += stripBytes;
  808.             if (p->progressProcRecord.progressProc) {
  809.                 if ( (result=CallICMProgressProc(p->progressProcRecord.progressProc,codecProgressUpdatePercent,
  810.                     FixDiv(y, numStrips),p->progressProcRecord.progressRefCon)) != noErr ) {
  811.                     result = codecAbortErr;
  812.                      goto bail;
  813.                 }
  814.             }
  815.         }
  816.     
  817.     
  818.     /* 
  819.      *
  820.      * otherwise - do the fast case. 
  821.      *
  822.      */
  823.          
  824.     } else {
  825.         SharedGlobals *sg = (*glob)->sharedGlob;
  826.         short    tRowBytes = rowBytes<<1;
  827.         
  828.         SwapMMUMode(&mmuMode);
  829.         for ( y=numStrips; y--; ) {
  830.             DecompressStrip(cDataPtr,baseAddr,rowBytes,width,sg);
  831.             baseAddr += tRowBytes;
  832.             cDataPtr += stripBytes;
  833.         }
  834.         SwapMMUMode(&mmuMode);
  835.     }
  836.     
  837.     /* 
  838.      *
  839.      *  IMPORTANT: update pointer to data in params, so when we get the  next
  840.      *  band we'll be at the right place in our data.
  841.      *  
  842.      */
  843.     
  844.     p->data = cDataPtr;
  845.     
  846.     if ( p->conditionFlags & codecConditionLastBand ) {
  847.         /* Tie up any loose ends on the last band of the frame, if we had any */
  848.     }
  849.  
  850. bail:
  851.     /*    If there is a progress proc, give it a close call at the end of this band. */
  852.  
  853.     if (p->progressProcRecord.progressProc)
  854.         CallICMProgressProc(p->progressProcRecord.progressProc,codecProgressClose,0,
  855.             p->progressProcRecord.progressRefCon);
  856.     return(result);
  857. }
  858.  
  859.  
  860. /************************************************************************************ 
  861.  *    CDGetCodecInfo allows us to return information about ourselves to the codec manager.
  862.  *    
  863.  *    There will be a tool for determining appropriate values for the accuracy, speed
  864.  *    and level information. For now we estimate with scientific wild guessing.
  865.  *
  866.  *  The info is stored as a resource in the same file with our component.
  867.  */
  868.  
  869. pascal ComponentResult
  870. CDGetCodecInfo(Handle storage,CodecInfo *info)
  871. {
  872.     Globals **glob = (Globals **)storage;
  873.  
  874.     if ( info == nil ) 
  875.         return(paramErr);
  876.     BlockMove((Ptr)*((*glob)->sharedGlob)->info,(Ptr)info,sizeof(CodecInfo));
  877.     return(noErr);
  878. }
  879.  
  880.  
  881. /************************************************************************************ 
  882.  *    When CDGetSimilarity is called, we return the percent of the compressed image A that
  883.  *    is different from compressed image B. This can be used by applications that use sequence
  884.  *    dynamics as an indicator for editing image sequences.
  885.  *    
  886.  *    If the codec cannot do a direct similarity comparison, the ICM decompresses image A and
  887.  *    do a comparison with image B.  This call is provided so that a codec can save the time
  888.  *    of the intermediate decompress if it can do the comparison directly.
  889.  */
  890.  
  891. pascal ComponentResult
  892. CDGetSimilarity(Handle storage,PixMapHandle src,const Rect *srcRect,ImageDescriptionHandle desc,
  893.                 Ptr data,Fixed *similarity)
  894. {
  895. #pragma    unused(storage,src,srcRect,desc,data,similarity)
  896.  
  897.     /*    This call is not implemented yet, which is okay, because its not used very much and is not mandatory */
  898.  
  899.     return(codecUnimpErr);
  900. }
  901.  
  902.  
  903. /************************************************************************************ 
  904.  *    When CDGetCompressedImageSize is called, we return the size in bytes of the given compressed
  905.  *    data ( for one image frame).
  906.  */
  907.  
  908. pascal ComponentResult
  909. CDGetCompressedImageSize(Handle storage,ImageDescriptionHandle desc,Ptr data,long dataSize,
  910.     ICMDataProcRecordPtr dataProc,long *size)
  911. {
  912. #pragma    unused(storage,data,dataSize,dataProc)
  913.  
  914.     short    width =(*desc)->width;
  915.     short    height = (*desc)->height;
  916.     
  917.     if ( size == nil )
  918.         return(paramErr);
  919.         
  920.     /*
  921.      *    Our data has a size which is deterministic based on the image size. If it were not we
  922.      *    could encode the size in the compressed data, or figure it out by walking the
  923.      *    compressed data.
  924.      */
  925.      
  926.     *size = ((width+1)/2) * 5 * ((height+1)/2);
  927.     return(noErr);
  928. }
  929.  
  930.  
  931. /************************************************************************************ 
  932.  *    When CDGetMaxCompressionSize is called, we return the maximum size the compressed data for
  933.  *    the given image would be in bytes.
  934.  */
  935.  
  936. pascal ComponentResult
  937. CDGetMaxCompressionSize(Handle storage,PixMapHandle src,const Rect *srcRect,short depth,
  938.     CodecQ quality,long *size)
  939. {
  940. #pragma    unused(storage,src,depth,quality)
  941.     
  942.     short width = srcRect->right - srcRect->left;
  943.     short height = srcRect->bottom - srcRect->top;
  944.  
  945.     /*    we always end up with a fixed size. If we did not, we would return the worst case size */
  946.     
  947.     *size = ((width+1)/2) * 5 * ((height+1)/2);    
  948.  
  949.     return(noErr);
  950. }
  951.  
  952.  
  953. /************************************************************************************ 
  954.  *    When CDGetCompressionTime is called, we return the approximate time for compressing
  955.  *    the given image would be in milliseconds. We also return the closest actual quality
  956.  *    we can handle for the requested value.
  957.  */
  958.  
  959. pascal ComponentResult
  960. CDGetCompressionTime(Handle storage,PixMapHandle src,const Rect *srcRect,short depth,
  961.         CodecQ *spatialQuality,CodecQ *temporalQuality,unsigned long *time)
  962. {
  963. #pragma    unused(storage,src,srcRect,depth)
  964.  
  965.     if (time)
  966.         *time = 0;                                    /* we don't know how many msecs */
  967.  
  968.     if (spatialQuality)
  969.         *spatialQuality = codecNormalQuality;        /* we have only one quality level for now */
  970.     
  971.     if (temporalQuality)
  972.         *temporalQuality = 0;                        /* we cannot do temporal compression */
  973.  
  974.     return(noErr);
  975. }
  976.  
  977.  
  978. /************************************************************************************ 
  979.  *    When CDTrimImage is called, we take the given compressed data and return only the portion
  980.  *    which is represented by the trimRect. We can return a little more if we have too, but we
  981.  *    need only return enough so that the image in trimRect is properly displayed. We then
  982.  *    adjust the rectangle to corresond to the same rectangle in the new trimmed data.
  983.  */
  984.  
  985. pascal ComponentResult
  986. CDTrimImage(Handle storage,ImageDescriptionHandle desc,Ptr inData,long inDataSize,
  987.         ICMDataProcRecordPtr dataProc,Ptr outData,long outDataSize,ICMFlushProcRecordPtr flushProc,
  988.         Rect *trimRect,ICMProgressProcRecordPtr progressProc)
  989. {
  990. #pragma    unused(storage,inDataSize)
  991.  
  992.     Rect    rect = *trimRect;
  993.     char    *dataP,*startP;
  994.     short    trimOffTop;
  995.     short    trimOffBottom;
  996.     short    trimOffLeft;
  997.     short    trimOffRight;
  998.     short    bytesOffLeft;
  999.     short    newHeight,newWidth;
  1000.     long    size;
  1001.     short    stripBytes;
  1002.     short    newStripBytes;
  1003.     short    y;
  1004.     OSErr    result = noErr;
  1005.     
  1006.         
  1007.     if ( dataProc->dataProc == nil )
  1008.         dataProc = nil;
  1009.     if ( flushProc->flushProc == nil )
  1010.         flushProc = nil;
  1011.     if ( progressProc->progressProc == nil )
  1012.         progressProc = nil;
  1013.     if ( progressProc ) 
  1014.         CallICMProgressProc(progressProc->progressProc,codecProgressOpen,0,progressProc->progressRefCon);
  1015.  
  1016.     dataP = inData;
  1017.     newHeight = (*desc)->height;
  1018.     newWidth = (*desc)->width;
  1019.     stripBytes = ((newWidth+1)>>1) * 5;            /* the number of bytes in a strip (2-scanlines/strip) */
  1020.     
  1021.     /* figure out how many 2x2 blocks we want to strip from each side of the image */
  1022.  
  1023.     trimOffTop = rect.top>>1;
  1024.     trimOffBottom  = (newHeight - rect.bottom) >> 1;
  1025.     trimOffLeft = rect.left>>1;
  1026.     trimOffRight  = (newWidth - rect.right) >> 1;
  1027.  
  1028.     /* point to the start of the first strip we are using */
  1029.  
  1030.     startP  = dataP + stripBytes * trimOffTop;
  1031.  
  1032.  
  1033.     /* make the trim values pixel based */
  1034.     
  1035.     trimOffLeft <<= 1;
  1036.     trimOffTop <<= 1;
  1037.     trimOffBottom <<= 1;
  1038.     trimOffRight <<= 1;
  1039.     
  1040.     /* calculate new height and width */
  1041.     
  1042.     newHeight -= trimOffTop + trimOffBottom;
  1043.     newWidth -=  trimOffLeft + trimOffRight;
  1044.     
  1045.     /* calc size in bytes of strips of the new width */
  1046.     
  1047.     newStripBytes = ((newWidth+1)>>1) * 5;        
  1048.  
  1049.     /* figure number of bytes to toss at the beginning of each strip  */
  1050.     
  1051.     bytesOffLeft = (trimOffLeft>>1) * 5;
  1052.  
  1053.     /* figure size of new trimmed image */
  1054.     
  1055.     size = newStripBytes * (newHeight>>1);
  1056.     
  1057.     /* make sure it's gonna fit */
  1058.     
  1059.     if ( size > outDataSize )  {
  1060.         result = codecErr;
  1061.         goto bail;
  1062.     }
  1063.         
  1064.     /* now go through the strips and copy the needed portion of each to the new data */
  1065.  
  1066.     if (  dataProc ) {
  1067.         short rightBytes = stripBytes - newStripBytes - bytesOffLeft;
  1068.         for ( y=0; y < trimOffTop; y++ ) {
  1069.             if ( (result=CallICMDataProc(dataProc->dataProc,&inData,stripBytes,dataProc->dataRefCon)) != noErr )
  1070.                 goto bail;
  1071.             inData += stripBytes;
  1072.             if (progressProc ) {
  1073.                 if ( (result=CallICMProgressProc(progressProc->progressProc,codecProgressUpdatePercent,
  1074.                     FixDiv(y, (*desc)->height),progressProc->progressRefCon)) != noErr)  {
  1075.                     result = codecAbortErr;
  1076.                     goto bail;
  1077.                 }
  1078.             }
  1079.         }
  1080.         for ( y=0; y < newHeight; y+= 2) {
  1081.             if ( bytesOffLeft ) {
  1082.                 if ( (result=CallICMDataProc(dataProc->dataProc,&inData,bytesOffLeft,dataProc->dataRefCon)) != noErr )
  1083.                     goto bail;
  1084.                 inData += bytesOffLeft;
  1085.             }
  1086.             if ( (result=CallICMDataProc(dataProc->dataProc,&inData,newStripBytes,dataProc->dataRefCon)) != noErr )
  1087.                 goto bail;
  1088.             if (  flushProc ) {
  1089.                 if ( (result=CallICMFlushProc(flushProc->flushProc,inData,newStripBytes,flushProc->flushRefCon)) != noErr ) {
  1090.                     result = codecSpoolErr;
  1091.                     goto bail;
  1092.                 }
  1093.             }
  1094.             else {
  1095.                 BlockMove(inData,outData,newStripBytes);
  1096.                 outData += newStripBytes;
  1097.             }
  1098.             inData += newStripBytes;
  1099.             if ( rightBytes ) {
  1100.                 if ( (result=CallICMDataProc(dataProc->dataProc,&inData,rightBytes,dataProc->dataRefCon)) != noErr ) {
  1101.                     result = codecSpoolErr;
  1102.                     goto bail;
  1103.                 }
  1104.                 inData += rightBytes;
  1105.             }
  1106.             if (progressProc) {
  1107.                 if ( (result=CallICMProgressProc(progressProc->progressProc,codecProgressUpdatePercent,
  1108.                     FixDiv((trimOffTop + y),(*desc)->height),progressProc->progressRefCon)) != noErr ) {
  1109.                     result = codecAbortErr;
  1110.                     goto bail;
  1111.                 }
  1112.             }
  1113.         }
  1114.     }
  1115.     else {
  1116.         inData += stripBytes * trimOffTop;
  1117.         for ( y=0; y < newHeight; y += 2, inData += stripBytes) {
  1118.             if (  flushProc ) {
  1119.                 if ( (result=CallICMFlushProc(flushProc->flushProc,inData + bytesOffLeft,newStripBytes,flushProc->flushRefCon)) != noErr ) {
  1120.                     result = codecSpoolErr;
  1121.                     goto bail;
  1122.                 }
  1123.             }
  1124.             else {
  1125.                 BlockMove(inData + bytesOffLeft,outData,newStripBytes);
  1126.                 outData += newStripBytes;
  1127.             }
  1128.             if (progressProc ) {
  1129.                 if ( (result=CallICMProgressProc(progressProc->progressProc,codecProgressUpdatePercent,
  1130.                     FixDiv((trimOffTop + y),(*desc)->height),progressProc->progressRefCon)) != noErr ) {
  1131.                     result = codecAbortErr;
  1132.                     goto bail;
  1133.                 }
  1134.             }
  1135.         }
  1136.     }
  1137.  
  1138.     /* adjust the rectangle to reflect our changes */
  1139.     
  1140.     trimRect->top -= trimOffTop;
  1141.     trimRect->bottom -= trimOffTop;
  1142.     trimRect->left -= trimOffLeft;
  1143.     trimRect->right -= trimOffLeft;
  1144.  
  1145.     /* return the new width and height in the image description and the size */
  1146.     
  1147.     (*desc)->height = newHeight;
  1148.     (*desc)->width = newWidth;
  1149.     (*desc)->dataSize = size;
  1150. bail:
  1151.     if ( progressProc ) 
  1152.         CallICMProgressProc(progressProc->progressProc,codecProgressClose,0,progressProc->progressRefCon);
  1153.  
  1154.     return(result);
  1155.  
  1156.  
  1157. }
  1158.  
  1159.     
  1160. #ifndef    HAS_ASM        /* we could do this part in assembly for speed if we desired */
  1161.  
  1162.  
  1163. #define    READPIXEL(n)                \
  1164.     l = *lp++;                        \
  1165.     r = (l>>16);                    \
  1166.     g = (l>>8);                        \
  1167.     b = l;                            \
  1168.     yt = (R_W*r + G_W*g + B_W*b);    \
  1169.     if ( yt > ((256L<<16)-1) ) yt = ((256L<<16)-1); \
  1170.     ys[n] = yt>>16;                    \
  1171.     y += yt;                        \
  1172.     u += r;                            \
  1173.     v += b;                        
  1174.  
  1175. #define    READPIXEL_TAB(n)                \
  1176.     l = *lp++;                        \
  1177.     r = (l>>16);                    \
  1178.     g = (l>>8);                        \
  1179.     b = l;                            \
  1180.     yt = (rwTable[r] + gwTable[g] + bwTable[b]);    \
  1181.     if ( yt > ((256L<<16)-1) ) yt = ((256L<<16)-1); \
  1182.     ys[n] = yt>>16;                    \
  1183.     y += yt;                        \
  1184.     u += r;                            \
  1185.     v += b;                        
  1186.  
  1187.  
  1188. pascal void
  1189. CompressStrip(char *data,char *baseAddr,short rowBytes,short len,SharedGlobals *sg)
  1190. {
  1191.  
  1192.     register long    l,*lp = (long *)baseAddr;
  1193.     register unsigned char     r,g,b;
  1194.     unsigned char    ys[4];
  1195.     register long    y,yt;
  1196.     short    u,v;
  1197.     short    rowLongs = (rowBytes>>2);
  1198.         
  1199.         
  1200.     
  1201.     
  1202.     len++;
  1203.     len>>=1;
  1204.     
  1205.     if ( sg->rgbwTable && *sg->rgbwTable  ) {
  1206.         long    *rwTable,*gwTable,*bwTable;
  1207.     
  1208.         rwTable = (long *)*sg->rgbwTable;
  1209.         gwTable = rwTable + 256;
  1210.         bwTable = rwTable + 512;
  1211.  
  1212.         while ( len-- > 0) {
  1213.             y = u = v = 0;
  1214.             READPIXEL_TAB(0);
  1215.             READPIXEL_TAB(1);
  1216.             lp += rowLongs-2;
  1217.             READPIXEL_TAB(2);
  1218.             READPIXEL_TAB(3);
  1219.             lp -= rowLongs;
  1220.         
  1221.             y >>= 16;
  1222.             u = (u - y)>>4;
  1223.             v = (v - y)>>4;
  1224.             
  1225.             l =  (long)(0xfc & (ys[0])) << 24;
  1226.             l |= (long)(0xfc & (ys[1])) << 18;
  1227.             l |= (long)(0xfc & (ys[2])) << 12;
  1228.             l |= (long)(0xfc & (ys[3])) <<  6;
  1229.             l |= u & 0xff;
  1230.             *(long *)data = l;
  1231.             data += sizeof(long);
  1232.             *data++ = v;
  1233.         }
  1234.     } else {
  1235.         while ( len-- > 0) {
  1236.             y = u = v = 0;
  1237.             READPIXEL(0);
  1238.             READPIXEL(1);
  1239.             lp += rowLongs-2;
  1240.             READPIXEL(2);
  1241.             READPIXEL(3);
  1242.             lp -= rowLongs;
  1243.         
  1244.             y >>= 16;
  1245.             u = (u - y)>>4;
  1246.             v = (v - y)>>4;
  1247.             
  1248.             l =  (long)(0xfc & (ys[0])) << 24;
  1249.             l |= (long)(0xfc & (ys[1])) << 18;
  1250.             l |= (long)(0xfc & (ys[2])) << 12;
  1251.             l |= (long)(0xfc & (ys[3])) <<  6;
  1252.             l |= u & 0xff;
  1253.             *(long *)data = l;
  1254.             data += sizeof(long);
  1255.             *data++ = v;
  1256.         }
  1257.     }
  1258. }
  1259.  
  1260.  
  1261.  
  1262.  
  1263. #define    WRITEPIXEL                \
  1264.     r = PIN(u+y);                \
  1265.     b = PIN(v+y);                \
  1266.     y <<= 16;                    \
  1267.     y -= r * R_W;                \
  1268.     y -= b * B_W;                \
  1269.     g = PIN(y / G_W);            \
  1270.     *lp++ = (long) ( (long) r <<16) | ( (long) g <<8) | b;    
  1271.  
  1272. #define    WRITEPIXEL_TAB            \
  1273.     r = PIN(u+y);                \
  1274.     b = PIN(v+y);                \
  1275.     y <<= 16;                    \
  1276.     y -= rwTable[r];        \
  1277.     y -= bwTable[b];        \
  1278.     g = giwTable[PIN(y>>16)];    \
  1279.     *lp++ = (long) ( (long) r <<16) | ( (long) g <<8) | b;    
  1280.     
  1281. pascal void
  1282. DecompressStrip(char *data,char *baseAddr,short rowBytes,short len,SharedGlobals *sg)
  1283. {
  1284.     register long    y;
  1285.     register unsigned char     r,g,b;
  1286.     register long    l,*lp;
  1287.     long     u,v;
  1288.     unsigned char    ys[4];
  1289.     short    rowLongs = (rowBytes>>2);
  1290.     short    blen = len;
  1291.  
  1292.     lp = (long *)baseAddr;
  1293.     blen++;
  1294.     blen >>= 1;
  1295.     
  1296.     if ( sg->rgbwTable && *sg->rgbwTable &&  sg->giwTable && *sg->giwTable ) {
  1297.         unsigned char    *giwTable;    
  1298.         long    *rwTable,*bwTable;
  1299.  
  1300.         giwTable = (unsigned char*)*sg->giwTable;
  1301.         rwTable = (long *)*sg->rgbwTable;
  1302.         bwTable = rwTable + 512;
  1303.         while ( blen-- > 0 ) {
  1304.             l = *(long *)data;
  1305.             data += sizeof(long);
  1306.             ys[0] = (0xfc & (l>>24));
  1307.             ys[1] = (0xfc & (l>>18));
  1308.             ys[2] = (0xfc & (l>>12));
  1309.             ys[3] = (0xfc & (l>>6));
  1310.             u = (char)l;
  1311.             v = *data++;
  1312.             u<<=2;
  1313.             v<<=2;
  1314.             y = ys[0];
  1315.             WRITEPIXEL_TAB;
  1316.             y = ys[1];
  1317.             WRITEPIXEL_TAB;
  1318.             lp += rowLongs - 2;
  1319.             y = ys[2];
  1320.             WRITEPIXEL_TAB;
  1321.             y = ys[3];
  1322.             WRITEPIXEL_TAB;
  1323.             lp -= rowLongs;
  1324.         }
  1325.     } else {
  1326.         while ( blen-- > 0 ) {
  1327.             l = *(long *)data;
  1328.             data += sizeof(long);
  1329.             ys[0] = (0xfc & (l>>24));
  1330.             ys[1] = (0xfc & (l>>18));
  1331.             ys[2] = (0xfc & (l>>12));
  1332.             ys[3] = (0xfc & (l>>6));
  1333.             u = (char)l;
  1334.             v = *data++;
  1335.             u<<=2;
  1336.             v<<=2;
  1337.             y = ys[0];
  1338.             WRITEPIXEL;
  1339.             y = ys[1];
  1340.             WRITEPIXEL;
  1341.             lp += rowLongs - 2;
  1342.             y = ys[2];
  1343.             WRITEPIXEL;
  1344.             y = ys[3];
  1345.             WRITEPIXEL;
  1346.             lp -= rowLongs;
  1347.         }
  1348.     }
  1349. }
  1350.  
  1351.  
  1352. #endif
  1353.  
  1354.  
  1355.